/*
 * Copyright (C) 2015 truth
 *
 * This program is non-free software, but you can redistribute it and/or modify
 * it if you are in hjj(Huangshi Hejianjiao) team.
 */
package com.truthbean.jutils.dao.impl;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.truthbean.jutils.dao.TBBaseDao;
import com.truthbean.jutils.dao.impl.apache.BaseDaoImpl;
import com.truthbean.jutils.dao.utils.Connector;
import com.truthbean.jutils.dao.utils.DBContext;

/**
 * @param <T>
 * @since Jan 15, 2015 11:20:28 AM
 * @author TruthBean
 */
public class TBBaseDaoImpl<T> extends BaseDaoImpl<T> implements TBBaseDao<T> {

    @Override
    public int[] batch(String sql, Object[][] args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        int[] rows = null;
        try {
            pstmt = conn.prepareStatement(sql);
            int count = args == null ? 0 : args.length;
            for (int j = 0; j < count; j++) {
                for (int i = 0; i < args[j].length; i++) {
                    pstmt.setObject(i + 1, args[j][i]);
                }
                /**
                 * jdbc自带的批量操作方法，存储sql操作集
                 */
                pstmt.addBatch();
            }
            /**
             * 执行sql操作集
             */
            rows = pstmt.executeBatch();
        } catch (SQLException ex) {
            /**
             * 通过java自带的日志类处理异常的结果
             */
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(null, pstmt);
        }
        return rows;
    }

    @Override
    public Map<Object, Object> get2V4MAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Map<Object, Object> result = new HashMap<>();
        try {
            /**
             * 对sql进行预处理
             */
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            while (rs.next()) {
                //将返回结果转换成Object对象是不规范的写法，建议使用反射获取对象类型
                result.put(rs.getObject(1), rs.getString(2));
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public Map<String, String[]> get2V4MAction(String sql, String split, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Map<String, String[]> result = new HashMap<>();
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            while (rs.next()) {
                result.put(rs.getString(1), rs.getString(2).split(split));
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public long insertAction(String sql, Object... args) {
        long id = 0;
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            /**
             * Statement.RETURN_GENERATED_KEYS 获取自动生成的键
             */
            pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            pstmt.executeUpdate();
            rs = pstmt.getGeneratedKeys();
            /**
             * autoGeneratedKeys - 指示是否应该返回自动生成的键的标志它�?
             * Statement.RETURN_GENERATED_KEYS �? Statement.NO_GENERATED_KEYS 之一
             */
            if (rs.next()) {
                id = rs.getLong(1);
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return id;
    }

    @Override
    public long updateAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        long rows = 0;
        try {
            pstmt = conn.prepareStatement(sql);
            int count = args == null ? 0 : args.length;
            for (int i = 0; i < count; i++) {
                pstmt.setObject(i + 1, args[i]);
            }
            rows = pstmt.executeUpdate();
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(null, pstmt);
        }
        return rows;
    }

    @Override
    public Object getSVAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Object result = null;
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            if (rs.next()) {
                result = rs.getObject(1);
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public String getSBVAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        String result = null;
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            if (rs.next()) {
                /**
                 * 必须将Blob二进制类型转换成String类型,才能正常显示其值
                 */
                Blob blob = rs.getBlob(1);
                int bolblen = (int) blob.length();
                byte[] data = blob.getBytes(1, bolblen);
                result = new String(data);
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public List<String> getSBV4LAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        List<String> result = new ArrayList<>();
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            if (rs.next()) {
                Blob blob = rs.getBlob(1);
                int bolblen = (int) blob.length();
                byte[] data = blob.getBytes(1, bolblen);
                result.add(new String(data));
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public Set<String> getSBV4SAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Set<String> result = new HashSet<>();
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            while (rs.next()) {
                Blob blob = rs.getBlob(1);
                int bolblen = (int) blob.length();
                byte[] data = blob.getBytes(1, bolblen);
                result.add(new String(data));
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public Set<Object> getSV4SAction(String sql, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Set<Object> result = new TreeSet<>();
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            while (rs.next()) {
                result.add(rs.getObject(1));
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public Set<String> getSVS4SAction(String sql, String split, Object... args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Set<String> result = new TreeSet<>();
        try {
            pstmt = conn.prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pstmt.setObject(i + 1, args[i]);
                }
            }
            rs = pstmt.executeQuery();
            while (rs.next()) {
                String tmp = rs.getString(1);
                //如果存在分词符，将String分成字符串
                if (tmp.contains(split)) {
                    String[] strs = tmp.split(split);
                    result.addAll(Arrays.asList(strs));
                } else {
                    result.add(tmp);
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(rs, pstmt);
        }
        return result;
    }

    @Override
    public int[] batchAction(String sql, Object[][] args) {
        Connection conn = DBContext.getInstance().get();
        PreparedStatement pstmt = null;
        int[] rows = null;
        try {
            pstmt = conn.prepareStatement(sql);
            int count = args == null ? 0 : args.length;
            for (int j = 0; j < count; j++) {
                for (int i = 0; i < args[j].length; i++) {
                    pstmt.setObject(i + 1, args[j][i]);
                }
                /**
                 * 批量加载到PreparedStatement中，统一处理
                 */
                pstmt.addBatch();
            }
            rows = pstmt.executeBatch();
        } catch (SQLException ex) {
            Logger.getLogger(TBBaseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Connector.close(null, pstmt);
        }
        return rows;
    }

}
